﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Caching;
using Gollie.WebCache;
using MySQL.Db;

namespace Gollie.DataTables
{
	public class UserActiveOfferdetailsPerVendorItem
	{
		public DateTime Aankoopdatum { get; set; }
		public decimal Tegoed { get; set; }
		public decimal Saldo { get; set; }
		public string Uitgaven { get; set; }
		public DateTime ExpiratieDatum { get; set; }
		public uint SaldoMutationId { get; set; }
		public DateTime Ingangsdatum { get; set; }
		public string Description { get; set; }
	}

	public class UserActiveOfferdetailsPerVendor : BaseBindable<UserActiveOfferdetailsPerVendorItem>
	{
		public Dictionary<uint, TransactionHistory> Transactions = new Dictionary<uint, TransactionHistory>();

		private UserActiveOfferdetailsPerVendor(uint userId, uint vendorId)
		{
			ResultSet resultSet = Database.Queries.GetUserActiveOfferdetailsPerVendor(userId, vendorId);

			this.AddDetails(resultSet);
		}

		private void AddDetails(ResultSet resultSet)
		{
			int numRows = resultSet.Count;
			if (numRows == 0)
				return;

			TransactionHistory history = new TransactionHistory();

			DateTime offerPurchaseDate = resultSet.GetDateTime(0, "purchasedate");
			DateTime validFrom = resultSet.GetDateTime(0, "validfrom");
			if (validFrom < offerPurchaseDate)
				validFrom = offerPurchaseDate;

			UserActiveOfferdetailsPerVendorItem newItem = CreateItem(resultSet, 0);

			uint saldoMutationId = newItem.SaldoMutationId;
			decimal saldo = resultSet.GetDecimal(0, "amount");
			int type = resultSet.GetInt32(0, "type");

			decimal startSaldo = 0;

			if (type==1) //deposit
				startSaldo = saldo;
			else
				history.AddDetails(offerPurchaseDate, saldo);

			int i = 1;

			while (i < numRows)
			{
				decimal amount = resultSet.GetDecimal(i, "amount");
				type = resultSet.GetInt32(i, "type");
				uint nextSaldoMutationId = resultSet.GetUInt32(i, "saldomutationid");
				if (nextSaldoMutationId != saldoMutationId)
				{
					newItem.Aankoopdatum = offerPurchaseDate;
					newItem.Tegoed = startSaldo;
					startSaldo = 0;
					newItem.Saldo = saldo;
					newItem.Uitgaven = ObjectFormatter.GetCurrencyString(history.Total);
					newItem.Ingangsdatum = validFrom;

					this.Add(newItem);

					this.Transactions[saldoMutationId] = history;
					history = new TransactionHistory();

					saldo = amount;
					saldoMutationId = nextSaldoMutationId;
					newItem = CreateItem(resultSet, i);
				}
				else
					saldo += amount;

				DateTime purchaseDate = resultSet.GetDateTime(i, "purchasedate");

				if (type == 1)
				{
					startSaldo = amount;
					offerPurchaseDate = purchaseDate;
					validFrom = resultSet.GetDateTime(i, "validfrom");
					if (validFrom < offerPurchaseDate)
						validFrom = offerPurchaseDate;

				}
				else
					history.AddDetails(purchaseDate, amount);

				i++;
			}

			this.Transactions[saldoMutationId] = history;

			newItem.Aankoopdatum = offerPurchaseDate;
			newItem.Tegoed = startSaldo;
			newItem.Saldo = saldo;
			newItem.Uitgaven = ObjectFormatter.GetCurrencyString(history.Total);
			newItem.Ingangsdatum = validFrom;

			this.Add(newItem);
		}

		private UserActiveOfferdetailsPerVendorItem CreateItem(ResultSet resultSet, int i)
		{
			return new UserActiveOfferdetailsPerVendorItem()
			{
				ExpiratieDatum = resultSet.GetDateTime(i, "expirationdate"),
				SaldoMutationId = resultSet.GetUInt32(i, "saldomutationid"),
				Description = resultSet.GetString(i, "description")
			};
		}

		public void Sum(out decimal startSaldo, out decimal saldo, out decimal uitgaven)
		{
			startSaldo = this.Sum(x => x.Tegoed);
			saldo = this.Sum(x => x.Saldo);
			uitgaven = saldo - startSaldo;
		}

		internal static UserActiveOfferdetailsPerVendor Instance(uint userId, uint vendorId)
		{
			OfferDetailsCollection allDetails = OfferDetailsCollection.GetInstance();

			OfferDetailsPerUserCollection detailsPerUser;
			if (allDetails.TryGetValue(userId, out detailsPerUser) == false)
			{
				detailsPerUser = new OfferDetailsPerUserCollection();
				allDetails[userId] = detailsPerUser;
			}

			UserActiveOfferdetailsPerVendor details;
			if (detailsPerUser.TryGetValue(vendorId, out details) == false)
			{
				details = new UserActiveOfferdetailsPerVendor(userId, vendorId);
				detailsPerUser[vendorId] = details;
			}

			return details;
		}

		internal static void RemoveFromCache(uint userId)
		{
			OfferDetailsCollection allDetails = DataCache.TryGetValue<OfferDetailsCollection>(OfferDetailsCollection.cacheName);
			if (allDetails == null)
				return;

			allDetails.Remove(userId);
		}

		internal static void RemoveFromCache(uint userId, uint vendorId)
		{
			OfferDetailsCollection allDetails = DataCache.TryGetValue<OfferDetailsCollection>(OfferDetailsCollection.cacheName);
			if (allDetails == null)
				return;

			OfferDetailsPerUserCollection detailsPerUser;
			if (allDetails.TryGetValue(userId, out detailsPerUser) == false)
				return;

			detailsPerUser.Remove(vendorId);
		}
	}

	public class TransactionHistoryItem
	{
		public DateTime Datum { get; set; }
		public decimal Bedrag { get; set; }
	}

	public class TransactionHistory : BaseBindable<TransactionHistoryItem>
	{
		public decimal Total = 0;

		public TransactionHistory()
		{
		}

		public void AddDetails(DateTime purchaseDate, decimal amount)
		{
			this.Add(new TransactionHistoryItem()
			{
				Datum = purchaseDate,
				Bedrag = amount
			});

			Total += amount;
		}
	}

	public class OfferDetailsPerUserCollection : Dictionary<uint, UserActiveOfferdetailsPerVendor>
	{ }

	public class OfferDetailsCollection : Dictionary<uint, OfferDetailsPerUserCollection>, ICacheable
	{
		internal static string cacheName = "useractiveofferdetailspervendor";

		public OfferDetailsCollection()
		{
			Policy = CacheDependencyBase.CreatePolicy(600);
		}

		public static OfferDetailsCollection GetInstance()
		{
			return (OfferDetailsCollection)DataCache.GetCacheableObject<OfferDetailsCollection>(cacheName);
		}

		public CacheItemPolicy Policy { get; set; }
		public void Initialize(params object[] args) { }
	}
}